import zmq
import threading
import time
import netifaces as ni #external
import cPickle
import json
import zlib
import sys
import signal
import logging
from collections import *
from random import choice
from utils import *
from easy_engine import *
from common.logger import *
interrupted = False
logger = logging.getLogger("guard")

#logging.basicConfig(format="[%(asctime)s] %(message)s", datefmt="%Y-%m-%d %H:%M:%S",level=logging.DEBUG)

pe=PolicyEngine()
ath=Auth()


def signal_handler(signum, frame):
    global interrupted
    interrupted = True
signal.signal(signal.SIGINT, signal_handler)

def init_engine():
    f=cPickle.load(open("test.po"))
    p=PolicyEngine()
    p.parse_policy(f)
    #print p.policy_store
    return p     



class PolicyGuard(threading.Thread):
    """docstring for PolicyGuard"""
    def __init__(self):
        threading.Thread.__init__ (self)
        self.id="None"
        self.context = zmq.Context()
        self.app_router = self.context.socket(zmq.ROUTER)
        self.app_dealer = self.context.socket(zmq.DEALER)
        self.ctr_router = self.context.socket(zmq.DEALER)
        self.ctr_dealer = self.context.socket(zmq.DEALER)
        self.app_list={}
        self.sockets=[]
        self.worker_no=10
        self.workers=[]
        self.st_time=0
        self.ed_time=0
        self.total_count=0
        self.miss_count=0
        
        
        self.msg=Message()
        self.poller = zmq.Poller()
        
        
        self.bind()
        self.register_clr()
        self.register_poll()
        self.init_worker()
        self.run()
        self.clean()


    def bind(self):
        self.app_router.bind('ipc:///tmp/guard_app.ipc')
        self.app_dealer.bind('inproc:///tmp/guard_worker.ipc')
        self.ctr_dealer.bind('inproc:///tmp/guard_ctr.ipc')

    def clean(self):
        self.app_router.close()
        self.app_dealer.close()
        self.ctr_dealer.close()
        self.ctr_router.close()
        self.context.term()
    
    def register_poll(self):
        self.poller.register(self.app_router, zmq.POLLIN)
        self.poller.register(self.app_dealer,  zmq.POLLIN)
        self.poller.register(self.ctr_router,  zmq.POLLIN)
        self.poller.register(self.ctr_dealer,  zmq.POLLIN)
        

    def register_clr(self):
        self.ctr_router.connect('tcp://localhost:5555')
        self.ctr_router.send(self.msg.msg_reg_new(self.id))
        while 1:
            msg = self.ctr_router.recv()
            msg=eval(msg)
            if msg[MSG_TYPE]==TYPE_REP_REGISTER:
                self.id=msg[MSG_SENDER]
                print msg
                self.ctr_router.close()
                self.ctr_router = self.context.socket(zmq.DEALER)
                self.ctr_router.setsockopt(zmq.IDENTITY, self.id)
                self.ctr_router.connect('tcp://localhost:5555')
                break

    def init_worker(self):
        for i in xrange(self.worker_no):
            worker = ServerWorker(self.context,self.app_router)
            worker.start()
            self.workers.append(worker)


    def event_app_reg(self,appid):
        msg={}
        msg[MSG_SENDER]=self.id
        msg[MSG_TYPE]=TYPE_APP_ADD
        msg[MSG_BODY]=appid
        #self.ctr_router.send(self.id,zmq.SNDMORE)
        print self.id, appid
        self.ctr_router.send(pack_msg(msg))
        t=self.ctr_router.recv()
        pass
    
    def run(self):
        self.st_time=time.time()
        while 1:
            sockets = dict(self.poller.poll(1))
            if self.app_router in sockets:
                if sockets[self.app_router] == zmq.POLLIN:
                    _id = self.app_router.recv()
                    msg = self.app_router.recv()
                    if _id not in self.app_list:
                        self.event_app_reg(_id)
                        self.app_list[_id]=1

                    """
                    app_registration()
                    """
                    self.app_dealer.send(_id, zmq.SNDMORE)
                    self.app_dealer.send(msg)
            if self.app_dealer in sockets:
                if sockets[self.app_dealer] == zmq.POLLIN:
                    _id = self.app_dealer.recv()
                    msg = self.app_dealer.recv()

                    self.app_router.send(_id, zmq.SNDMORE)
                    self.app_router.send(msg)

            if self.ctr_dealer in sockets:
                if sockets[self.ctr_dealer] == zmq.POLLIN:
                    _id = self.ctr_dealer.recv()
                    msg = self.ctr_dealer.recv()
                    logger.warning("Ask controller for help")
                    #print 'guard dont know what to do for the request from %s' % (_id)
                    self.miss_count+=1
                    #self.ctr_router.send(_id, zmq.SNDMORE)
                    self.ctr_router.send(msg_request(self.id,_id,msg))
 

            if self.ctr_router in sockets:
                if sockets[self.ctr_router] == zmq.POLLIN:
                    msg = self.ctr_router.recv()
                    msg=json.loads(msg)
                    if msg[MSG_TYPE]==TYPE_REP_MISSPOLICY:
                        reply=msg[MSG_BODY]
                        _id=msg[MSG_FROM]
                        logger.warning("Get response from controller: %s",reply)
                        self.app_router.send_string(_id, zmq.SNDMORE)
                        self.app_router.send_string(reply)

                    if msg[MSG_TYPE]==TYPE_POLICY_ADD:
                        policy=msg[MSG_BODY]["POLICY"]
                        pe.parse_policy(policy)
                        logger.debug("Guard %s add new policy sucessfully",self.id)
                        self.ctr_router.send(msg_ok(self.id,GUARD,USER))
                    if msg[MSG_TYPE]==TYPE_CREATE_USR:
                        info=msg[MSG_BODY]
                        ath.create_user(info[0],info[1],info[2])
                        logger.debug("Guard %s add new user sucessfully",self.id)
                        self.ctr_router.send(msg_ok(self.id,GUARD,USER))
        pass    




#logging.basicConfig(format="%(asctime)s %(message)s", datefmt="%Y-%m-%d %H:%M:%S",level=logging.INFO, filename='test.log',filemode='a') 


class ServerWorker(threading.Thread):
    """ServerWorker"""
    def __init__(self,context,sender):
        threading.Thread.__init__ (self)
        self.context = context
        self.sender = sender
        #self.msg=MSG()

    def run(self):
        worker = self.context.socket(zmq.DEALER)
        worker.connect('inproc:///tmp/guard_worker.ipc')

        err_dealer = self.context.socket(zmq.DEALER)
        err_dealer.connect('inproc:///tmp/guard_ctr.ipc')
        
        while 1:
            _id = worker.recv()
            msg = worker.recv()
            if msg.startswith("AUTH:"):
                tmp,a,u,k=msg.split(":")
                if ath.auth(a,u,k):
                    msg=str(ath.get_url(a,u))
                else:
                    msg="DENY"
            elif msg.startswith("DEBUG"):
                msg="DEBUG"
            else:
                
                tmsg=json.loads(msg)
                subject={}
                resource={}
                action={}

                action["action"]=tmsg["method"]

                account,uid,prx=tmsg["remote_user"].split(",")
                account,user=uid.split(":")
                subject["ip"]=tmsg["remote_addr"]
                subject["uid"]=uid
                subject["account"]=account
                subject["user"]=user

                resource["container"]=tmsg["container"]
                resource["obj"]=tmsg["obj"]
                resource["type"]=None
                if resource["obj"]:
                    resource["type"]=tmsg["obj"].split(".")[-1]

                resource["owner"]=uid

                if action["action"] =="PUT":
                    resource["create_time"]=time.time()
                    resource["modify_time"]=resource["create_time"]
                if action["action"] =="POST":
                    resource["modify_time"]=time.time()
                meta=[subject,resource,action]
                res=pe.lookup(meta)
                if res=="None":
                    err_dealer.send(_id,zmq.SNDMORE)
                    err_dealer.send(json.dumps(meta))
                    res=err_dealer.recv()
                msg=res
                logger.error("send back message %s,%s",_id,msg)
            worker.send(_id, zmq.SNDMORE)
            worker.send(msg)

            del msg

        worker.close()

if __name__ == '__main__':
    guard = PolicyGuard()
    st_time=time.time()

    guard.start()
    ed_time=time.time()
    print "sys time usage",ed_time-st_time